ATTACK //The attack datum. Contains all relevant data on an attack.
	var
		fSpecial	= 1 as num		/* unknown. has something to do with special attacks */
		ndice		= 7 as num		/* number of dice to roll */
		fRange		= 1 as num		/* can we do this attack when not adjacent? */
		attackType	= 7 as num		/* for description */
		plustodam	= 4 as num		/* an attack can be 2-5 */
		fSureHit	= 4 as num		/* currently only used for surtur */
		multiple	= 4 as num		/* so we can do two claws at once, etc. */
		dieType		= 4 as num		/* so we can do 3d6, 2d8, 4d4 etc. */
	New()
		fSpecial = args[1]
		ndice = args[2]
		fRange = args[3]
		attackType = args[4]
		plustodam = args[5]
		fSureHit = args[6]
		multiple = args[7]
		dieType = args[8]

mob
	monster
		proc

			DoMonsterAttack(mob/pc/M as mob, ATTACK/pattack)
				var/fNormal = FNormalDamage(pattack.attackType)
				var imult, cmult, chits;
				var/idstr = 0 // What ARE these for?!
				//var/dir; //Apparently got removed in the porting process

				// /* PlaySound(rgmonsubtypeinfo[src.subType].iSound) */

				for(cmult = pattack.multiple, imult < cmult, imult++)
					if(src.FMonsterHit(M, pattack))
							// OutHitSz(pmonster, pattack, &idstr) // WHAT is this?!?!
						if(!fNormal) // Damage will output strings, so do this here
							oview(src) - M << "[src] hits [M]"
							M << "[src] hits you"
						var/newidstr = src.DoMonsterDamage(M, pattack, idstr) // Evil pointers (&idstr)
						idstr = newidstr
						chits++
					else if(!fNormal) // Do miss here
						oview(src) - M << "[src] misses [M]"
						M << "[src] misses you"
						// OutMissSz(pmonster, pattack) // Guessing that these output strings like "You have missed."
					if(M.dead) // I guess. Need better death determinants, possibly
						return 0
				//Have to do with outputting strings, or something
				if(fNormal)
					if(cmult > 1 || chits)
						oview(src) - M << "[src] hits [M]"
						M << "[src] hits you"
						// OutHitSz(pmonster, pattack, cmult, chits) // I hate these.
					else if(cmult==1)
						oview(src) - M << "[src] misses [M]"
						M << "[src] misses you"
						// OutMissSz(pmonster, pattack) // I really hate these.
				//if(idstr)
					// OutDescIdstr(idstr, fFalse) // >:(
				M.AVMod -= AVMODPERATTACK // This used to be under an if(), but the if() is complex and probably
				                          //isn't worth porting(has to do with old time system)

/*********************************************************************
A level 1 monster has a 50% chance to hit a character with no armor.
Chance goes up 5% per level, and down 3% per ac of player. Attack
bonus ads 5% per plus. There is always a 1% chance of hitting the
player.
*********************************************************************/
			FMonsterHit(mob/pc/M as mob, ATTACK/pattack)
				var/tohit
				if(pattack.fSureHit)
					return True
				var/MONSUBTYPEINFO/MST = rgmonsubtypeinfo[src.subType]
				tohit = 265 - M.ac - M.AVMod + 10 * MST.level
				tohit = tohit * tohit / 1000
				if(tohit < 1)
					tohit = 1
				return(rand(100) < tohit)

			DoMonsterDamage(mob/pc/M, ATTACK/pattack, idstr) // The evil proc of long-complicatedness
				var damage, dieType, wRF, iattrib
				idstr = 0
				if(M.FPlayerImmune(pattack.attackType))
					idstr = IDSTRPImmune
					return idstr
				if(!pattack.fSpecial && FNormalDamage(pattack.attackType))
					dieType = pattack.dieType
					damage = pattack.ndice  /* always 1 hp per die */
					damage += roll(pattack.ndice, dieType)
					iattrib = mapAttackTypePAttrib[pattack.attackType]
					wRF = M.rgattrib[iattrib]
					if(iattrib != pattribNil && wRF)
						if(wRF > 0)
							idstr = IDSTRPImmune
							damage >> wRF
						else
							idstr = IDSTRPVulnerable
							damage <<= -wRF
					FDeadDoDamage(M, damage, idstr) //TODO: Create IFM proc.
													//HACK: IFM proc evil. Let's try NOT using it.
				else /* special attacks */
					// Heh, sorry. Too much. Will port later.
					// Hack: Cheap trick to keep from having to port code now.
					pattack.attackType = attackNormalHit
					pattack.fSpecial = 0
					return src.DoMonsterDamage(M, pattack, idstr)
					/* special attacks */
					switch (pattack.attackType)
						if(attackBreathFire)
						if(attackBreathLightning)
						if(attackBreathCold)
							/* dragon breath */
							damage = src.hp;
							iattrib = mapAttackTypePAttrib[pattack.attackType];
							wRF = M.rgattrib[iattrib]
							if (iattrib != pattribNil && wRF)
								if (wRF > 0)
									idstr = IDSTRPImmune;
									damage >>= wRF;
								else
									idstr = IDSTRPVulnerable;
									damage <<= -wRF;
							//FDeadDoDamage(damage, IdstrFromMst(src.subType, True))
							FDeadDoDamage(damage, idstr)
							//break;
							return
					/*	case attackBreathPoison:
							/* set daemon to take away hps every minute */
							damage = pmonster->hp;	/* damage divides over damge intervals*/
							FAddDaemon(&hdaemonlistFast, damage, actionPoison, 1, 0L);
							InvalidateStat(statHP);
							break;*/
						if(attackExpDrain)
							/* die type is the % to take */
							var/expLoss = M.experienceMax * pattack.dieType / 100
							/* check for player resistance */
							iattrib = mapAttackTypePAttrib[pattack.attackType];
							wRF = M.rgattrib[iattrib]
							if (iattrib != pattribNil && wRF)
								if (wRF > 0)
									idstr = IDSTRPImmune;
									expLoss >>= wRF;
								else
									idstr = IDSTRPVulnerable;
									expLoss <<= -wRF;
							M.LoseExperience(expLoss)
							//break;
							return
						/*if(attackStatDrain)
							// ndice gives number of 3 sided dice for amount to drain
							// plustodam is flags
							// dieType gets used for which stat to drain.
							dieType = 3;
							damage = pattack.ndice;	/* always 1 hp per die */
							damage += roll(ndice, dieType)
							// Drain life protects against stat/mana drain as well
							iattrib = mapAttackTypePAttrib[pattack.attackType];
							wRF = rgattrib[iattrib[
							if (iattrib != pattribNil && wRF)
								if (wRF > 0)
									idstr = IDSTRPImmune;
									damage >>= wRF;
								else
									idstr = IDSTRPVulnerable;
									damage <<= -wRF;
							damage = -damage;
							// damage now has amount to change stat by.
							ChangePlayerStat(actionStr + pattack.dieType, damage,
								pattack.plustodam, fTrue); // Get this in somehow
							break;*/
						/*if(attackManaDrain)
							dieType = pattack.dieType;
							damage = pattack.ndice;	/* always 1 hp per die */
							damage += roll(pattack.ndice, dieType)
							// Drain life protects against stat/mana drain as well
							iattrib = mapAttackTypePAttrib[pattack.attackType];
							wRF = rgattrib[iattrib]
							if (iattrib != pattribNil && wRF)
								if (wRF > 0)
									idstr = IDSTRPImmune;
									 damage >>= wRF;
								else
									idstr = IDSTRPVulnerable;
									damage <<= -wRF;
			#ifdef REVIEW
							/****
							This is bogus if mana is already negative, as it
							can be if int drops
							***/
							if (damage > M.mana)
								damage = M.mana;	// don't go negative
			#endif /* REVIEW */
							ChangePlayerStat(actionMana, -damage, 0, fTrue); // Get this proc ported
							break;*/

						/*case attackPoison1:
						case attackPoison2:
						case attackPoison3:
							/* set daemon to take away hp every minute */
							// dietype is length of daemon, 1,2,3 is number per minute
							FAddDaemon(&hdaemonlistSlow, pattack->dieType, actionPoison, pattack->attackType - attackPoison1 + 1, 0L);
							InvalidateStat(statHP);
							break;*/
						/*case attackParalysis:
							/* Set cmdCache so we advance a minute of time on the player */
							cmdCache = cmdAdvanceTime;
							timePending = 600;
							break;*/
						/*if(attackHPDrain)
							// ndice gives number of dice for amount to drain
							// plustodam is flags
							dieType = pattack.dieType;
							damage = pattack.ndice;	/* always 1 hp per die */
							damage += roll(pattack.ndice, dieType)
							// Drain life protects against hp/stat/mana drain as well
							iattrib = mapAttackTypePAttrib[pattack.attackType];
							wRF = rgattrib[iattrib]
							if (iattrib != pattribNil && wRF)
								if (wRF > 0)
									idstr = IDSTRPImmune;
									damage >>= wRF;
								else
									idstr = IDSTRPVulnerable;
									damage <<= -wRF;
							damage = -damage;
							// damage now has amount to change hp by by.
							ChangePlayerStat(actionHitPoints, damage,
								pattack->plustodam, fTrue);
							break;*/
						else
							//Since not all code is ported, do the default if rest fails
							pattack.attackType = attackNormalHit
							pattack.fSpecial = 0
							return src.DoMonsterDamage(M, pattack, idstr)
						/*	Assert(0,"FDeadDoDamage: bad special attack");
							break;*/
				return idstr



/*					switch (pattack->attackType)
					{
					case attackBreathFire:
					case attackBreathLightning:
					case attackBreathCold:
						/* dragon breath */
						damage = pmonster->hp;
						iattrib = mapAttackTypePAttrib[pattack->attackType];
						if (iattrib != pattribNil && (wRF = rgattrib[iattrib]))
							{
							if (wRF > 0)
								{
								*pidstr = IDSTRPImmune;
								damage >>= wRF;
								}
							else
								{
								*pidstr = IDSTRPVulnerable;
								damage <<= -wRF;
								}
							}
						FDeadDoDamage(damage, IdstrFromMst(pmonster->subType, fTrue));
						break;
					case attackBreathPoison:
						/* set daemon to take away hps every minute */
						damage = pmonster->hp;	/* damage divides over damge intervals*/
						FAddDaemon(&hdaemonlistFast, damage, actionPoison, 1, 0L);
						InvalidateStat(statHP);
						break;
					case attackExpDrain:
						/* die type is the % to take */
						{
						long expLoss = player.experienceMax * (long)pattack->dieType / (long) 100;
						/* check for player resistance */
						iattrib = mapAttackTypePAttrib[pattack->attackType];
						if (iattrib != pattribNil && (wRF = rgattrib[iattrib]))
							{
							if (wRF > 0)
								{
								*pidstr = IDSTRPImmune;
								expLoss >>= wRF;
								}
							else
								{
								*pidstr = IDSTRPVulnerable;
								expLoss <<= -wRF;
								}
							}
						LoseExperience(expLoss);
						break;
						}
					case attackStatDrain:
						// ndice gives number of 3 sided dice for amount to drain
						// plustodam is flags
						// dieType gets used for which stat to drain.
						dieType = 3;
						damage = pattack->ndice;	/* always 1 hp per die */
						for (idie = 0; idie < pattack->ndice; idie++)
							damage += random(dieType);
						// Drain life protects against stat/mana drain as well
						iattrib = mapAttackTypePAttrib[pattack->attackType];
						if (iattrib != pattribNil && (wRF = rgattrib[iattrib]))
							{
							if (wRF > 0)
								{
								*pidstr = IDSTRPImmune;
								 damage >>= wRF;
								}
							else
								{
								*pidstr = IDSTRPVulnerable;
								damage <<= -wRF;
								}
							}
						damage = -damage;
						// damage now has amount to change stat by.
						ChangePlayerStat(actionStr + pattack->dieType, damage,
							pattack->plustodam, fTrue);
						break;
					case attackManaDrain:
						dieType = pattack->dieType;
						damage = pattack->ndice;	/* always 1 hp per die */
						for (idie = 0; idie < pattack->ndice; idie++)
							damage += random(dieType);
						// Drain life protects against stat/mana drain as well
						iattrib = mapAttackTypePAttrib[pattack->attackType];
						if (iattrib != pattribNil && (wRF = rgattrib[iattrib]))
							{
							if (wRF > 0)
								{
								*pidstr = IDSTRPImmune;
								 damage >>= wRF;
								}
							else
								{
								*pidstr = IDSTRPVulnerable;
								damage <<= -wRF;
								}
							}
		#ifdef REVIEW
						/****
						This is bogus if mana is already negative, as it
						can be if int drops
						***/
						if (damage > player.mana)
							damage = player.mana;	// don't go negative
		#endif /* REVIEW */
						ChangePlayerStat(actionMana, -damage, 0, fTrue);
						break;

					case attackPoison1:
					case attackPoison2:
					case attackPoison3:
						/* set daemon to take away hp every minute */
						// dietype is length of daemon, 1,2,3 is number per minute
						FAddDaemon(&hdaemonlistSlow, pattack->dieType, actionPoison, pattack->attackType - attackPoison1 + 1, 0L);
						InvalidateStat(statHP);
						break;
					case attackParalysis:
						/* Set cmdCache so we advance a minute of time on the player */
						cmdCache = cmdAdvanceTime;
						timePending = 600;
						break;
					case attackHPDrain:
						// ndice gives number of dice for amount to drain
						// plustodam is flags
						dieType = pattack->dieType;
						damage = pattack->ndice;	/* always 1 hp per die */
						for (idie = 0; idie < pattack->ndice; idie++)
							damage += random(dieType);
						// Drain life protects against hp/stat/mana drain as well
						iattrib = mapAttackTypePAttrib[pattack->attackType];
						if (iattrib != pattribNil && (wRF = rgattrib[iattrib]))
							{
							if (wRF > 0)
								{
								*pidstr = IDSTRPImmune;
								 damage >>= wRF;
								}
							else
								{
								*pidstr = IDSTRPVulnerable;
								damage <<= -wRF;
								}
							}
						damage = -damage;
						// damage now has amount to change hp by by.
						ChangePlayerStat(actionHitPoints, damage,
							pattack->plustodam, fTrue);
						break;
					default:
						Assert(0,"FDeadDoDamage: bad special attack");
						break; */

			FDeadDoDamage(mob/pc/M, damage, idstr)
				var/fDead = false
				M.hp -= damage
				if(M.hp  <= 0)
					// TODO! KILL PLAYER HERE!!
					M.dead = true
					fDead = true
				// InvalidateStat(statHP) - not ported, probably not useful
				return fDead

mob
	pc
		proc
			FPlayerImmune(attackType)
				var/iattrib = mapAttackTypePAttrib[attackType]
				if(iattrib == pattribNil)
					return False
				else
					switch(attackType)
						if(attackFear)
						if(attackConfusion)
						if(attackSlow)
						if(attackBlind)
						if(attackPoison1)
						if(attackPoison2)
						if(attackPoison3)
							/* these are where resistance = immunity */
							return (rgattrib[iattrib] > 0)
					return False // Used to be else return False

proc
	FNormalDamage(attackType)
		switch(attackType)
			if(attackNormalHit)
			if(attackFire)
			if(attackCold)
			if(attackAcid)
			if(attackLightning)
			if(attackClaw)
			if(attackBite)
			if(attackTrample)
			if(attackTailLash)
			if(attackThrowBoulder)
			if(attackThrowIceball)
			if(attackHurlTailSpike)
			if(attackBuffet)
			if(attackDisease)
			if(attackFireArrow)
			if(attackWhirlwind)
				return True
			if(attackPoison1)
			if(attackPoison2)
			if(attackPoison3)
			if(attackExpDrain)
			if(attackStatDrain)
			if(attackObjDrain)
			if(attackObjDestroy)
			if(attackObjSteal)
			if(attackManaDrain)
			if(attackFear)
			if(attackConfusion)
			if(attackSlow)
			if(attackBlind)
			if(attackSpell)
			if(attackParalysis)
			if(attackHPDrain)
				return False
		return True //Used to be else return True, but I think that there's some C thing

proc
/*	IdstrFromMst(mst, fFullName)
		var/idstr
		idstr = mpMstIdstr[mst].idstr //Warning. Will generate a stupid BYOND compiler error.
		if(fFullName && mpMstIdstr[mst].fFullName) //Ditto. Find out what's in that list!
			idstr++*/

	AttackTypeToPAttrib(ATTACK/attack)
		return mapAttackTypePAttrib[attack]